/***************************************************************************
 *   Copyright (C) 2008 by Tomasz Dubik                                    *
 *   tdubik@gmail.com                                                      *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <QDebug>
#include <QHeaderView>
#include <QTreeWidgetItem>
#include <QTextTable>
#include <QPrinter>
#include <QPrintDialog>
#include <QKeyEvent>
#include <QMessageBox>
#include <QWidget>
#include <QSettings>
#include <QUrl>

#include "mainwindowimpl.h"
#include "newitemdialogimpl.h"
#include "taskcontainer.h"
#include "task.h"
#include "globals.h"
#include "common.h"


//TODO:1.1. select properly item after editing/deleting/adding
//TODO:2. translation
//TODO:4 Shortcuts


MainWindowImpl::MainWindowImpl( QWidget * parent, Qt::WFlags f) 
	: QMainWindow(parent, f), m_bExit(false)
{

	//PriorityList << "Hi" << "Mid" << "Low";
	PriorityList[0] = "Hi";
	PriorityList[1] = "Mid";
	PriorityList[2] = "Low";
	
	setupUi(this);
	
	m_toolbar->addAction(actionAdd);
	m_toolbar->addAction(actionEdytuj);
	m_toolbar->addAction(actionUsun);
	m_toolbar->addAction(actionOba);

	/*
	m_toolbar->addSeparator();
	m_toolbar->addAction(actionWork);
	m_toolbar->addAction(actionPersonal);
	*/
	
	m_appSettings = new QSettings(QSettings::UserScope,QString("QWhaTToDoOrg"),APPLICATION_NAME );
	m_headers << tr("Priority") << tr("Tasks") <<  tr("date") << tr("done");
	setView(m_officeTasksTree);
	setView(m_privateTasksTree);
	
	//loadTreeConfigSettings();
	m_container = new TaskContainer(this);
	m_ftpHandler = new FtpHandler(this);

	loadConfigSettings();
	loadUiSettings();
	initializeSystemTray();
	setConnections();	
	
	m_container->loadData(DATAFILE);
	m_currentList = m_officeTasksTree;
	
}

MainWindowImpl::~MainWindowImpl()
{
	delete m_appSettings;
	delete m_trayIcon;
	delete m_container;
	delete m_trayIconMenu;
	delete m_ftpHandler;
    delete m_pNewItemDialog;
}

void MainWindowImpl::setView(QTreeWidget* tree)
{
	tree->setHeaderLabels(m_headers);
	QHeaderView* header = tree->header();
	header->setResizeMode( QHeaderView::Fixed );
	header->resizeSection(0, 90);
	header->resizeSection(1, 450);
	header->resizeSection(2, 70);
	header->resizeSection(3, 10);
	header->setMovable( false );
	tree->setRootIsDecorated(false);
	tree->setSelectionBehavior( QAbstractItemView::SelectRows );
	tree->setSelectionMode(QAbstractItemView::SingleSelection);
	tree->setAlternatingRowColors( true );
}

void MainWindowImpl::setConnections()
{
	//menu action
	connect(actionAdd,SIGNAL(triggered()), this, SLOT(addTask()));
	connect(actionEdytuj,SIGNAL(triggered()), this, SLOT(editTask()));
	connect(actionUsun, SIGNAL(triggered()), this, SLOT(deleteTask()));
	connect(actionWork, SIGNAL(triggered()), this, SLOT(printWork()));
	connect(actionPersonal, SIGNAL(triggered()), this, SLOT(printPersonal()));
	connect(actionOba, SIGNAL(triggered()), this, SLOT(printBoth()));
	connect(actionAbout_QT, SIGNAL(triggered()), this, SLOT(aboutQt()));
	connect(actionAbout_QWhatToDo, SIGNAL(triggered()), this, SLOT(aboutQWhatToDo()));
	connect(actionQuit, SIGNAL(triggered()), this, SLOT(close()));
	connect(actionConfiguration, SIGNAL(triggered()), this, SLOT(configureDlg()));
	connect(actionDownload_tasks, SIGNAL(triggered()), this, SLOT(ftpDownload()));
	connect(actionUpload_tasks, SIGNAL(triggered()), this, SLOT(ftpUpload()));
	
	connect(m_container, SIGNAL( taskAdded( Task&)), this, SLOT( addTaskToList( Task&)));

	//lists
	connect(m_officeTasksTree, SIGNAL( itemClicked (QTreeWidgetItem*,int )), this, SLOT(officeItemClicked(QTreeWidgetItem*,int )));
	connect(m_privateTasksTree, SIGNAL( itemClicked (QTreeWidgetItem*,int )), this, SLOT(privateItemClicked(QTreeWidgetItem*,int )));
	connect(m_officeTasksTree, SIGNAL( itemActivated ( QTreeWidgetItem*,int)), this, SLOT(officeItemClicked(QTreeWidgetItem*,int )));
	connect(m_privateTasksTree, SIGNAL( itemActivated ( QTreeWidgetItem*,int)), this, SLOT(privateItemClicked(QTreeWidgetItem*,int )));
	connect(m_officeTasksTree, SIGNAL(itemDoubleClicked ( QTreeWidgetItem *, int )), this, SLOT( editItem(QTreeWidgetItem*,int)));
	connect(m_privateTasksTree, SIGNAL(itemDoubleClicked ( QTreeWidgetItem *, int )), this, SLOT( editItem(QTreeWidgetItem*,int)));
	connect(m_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
	//ftp
	connect(m_ftpHandler, SIGNAL( ftpDone()), this, SLOT( ftpDone()));
	connect(m_ftpHandler, SIGNAL( ftpError(const QString&)), SLOT( ftpError(const QString&)));
	connect(m_ftpHandler, SIGNAL( ftpProgress(qint64, qint64)), SLOT( ftpProgress(qint64, qint64)));	
}

void MainWindowImpl::loadConfigSettings()
{
	m_ftpHandler->setHost( m_appSettings->value( AppSettings_FtpHost ).toString( ));
	m_ftpHandler->setUsername(m_appSettings->value( AppSettings_FtpUsername ).toString( ));
	m_ftpHandler->setPassword(m_appSettings->value( AppSettings_FtpPassword ).toString( ));
	m_ftpHandler->setUsePassiveMode(m_appSettings->value( AppSettings_FtpPassive ).toBool( ));
	m_savePassword = m_appSettings->value( AppSettings_FtpSavePassword ).toBool( );
}

void MainWindowImpl::saveConfigSettings()
{
	m_appSettings->setValue( AppSettings_FtpHost, m_ftpHandler->host());
	m_appSettings->setValue( AppSettings_FtpUsername, m_ftpHandler->username());
	m_appSettings->setValue( AppSettings_FtpPassword, m_ftpHandler->password());
	m_appSettings->setValue( AppSettings_FtpSavePassword, m_savePassword);
	m_appSettings->setValue( AppSettings_FtpPassive, m_ftpHandler->usePassiveMode());
	m_appSettings->sync();
}

void MainWindowImpl::saveTreeConfigSettings()
{
	QHeaderView* header = m_officeTasksTree->header();
	m_appSettings->setValue( UI_TREE_1_SIZE, header->sectionSize(0) );
	m_appSettings->setValue( UI_TREE_2_SIZE, header->sectionSize(1) );
	m_appSettings->setValue( UI_TREE_3_SIZE, header->sectionSize(2) );
	m_appSettings->setValue( UI_TREE_4_SIZE, header->sectionSize(3) );

}

void MainWindowImpl::loadTreeConfigSettings()
{
	setSectionSize( 0, m_appSettings->value( UI_TREE_1_SIZE ).toInt() );
	setSectionSize( 1, m_appSettings->value( UI_TREE_2_SIZE ).toInt() );
	setSectionSize( 2, m_appSettings->value( UI_TREE_3_SIZE ).toInt() );
	setSectionSize( 3, m_appSettings->value( UI_TREE_4_SIZE ).toInt() );
}

void MainWindowImpl::setSectionSize(int section, int size)
{
	QHeaderView* header = m_officeTasksTree->header();
	if( size <= 0 )
	{
		switch(section)
		{
			case 0:
				size = 90;
				break;
			case 1:
				size = 400;
				break;
			case 2:
				size = 150;
				break;
			case 3:
				size = 30;
				break;
			default:
				size = 100;
		}
	}
	header->resizeSection(section,size);
	header = m_privateTasksTree->header();
	header->resizeSection(section,size);
}

void MainWindowImpl::initializeSystemTray()
{
	if( !QSystemTrayIcon::isSystemTrayAvailable() )
	{
		qDebug() << "No systemtray found";		
	}
	else
	{		
		m_trayIcon = new QSystemTrayIcon(this);
		m_trayIconMenu = new QMenu(this);
		// actions
		m_minimizeAction = new QAction(tr("&Hide"), m_trayIconMenu);
		m_restoreAction = new QAction(tr("&Restore"), m_trayIconMenu);
		m_quitAction = new QAction(tr("&Quit"), m_trayIconMenu);
		connect(m_minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));
		connect(m_restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));
		connect(m_quitAction, SIGNAL(triggered()), this, SLOT(close()));
		m_trayIconMenu->addAction(m_minimizeAction);
		m_trayIconMenu->addAction(m_restoreAction);
		m_trayIconMenu->addAction(m_quitAction);

		m_trayIcon->setContextMenu( m_trayIconMenu );
		m_trayIcon->setIcon( QIcon( ":/main.png") );
		m_trayIcon->show();

	}
}

void MainWindowImpl::iconActivated(QSystemTrayIcon::ActivationReason reason)
{	
	if(reason != QSystemTrayIcon::Context)
	{
		if(this->isVisible())
			hide();
		else if(this->isHidden())
			showNormal();
	}
};

void MainWindowImpl::closeEvent(QCloseEvent * event)
{	
	qDebug() << m_bExit;
	if(! m_bExit )
	{
		event->ignore();
		hide();
	}
}

void MainWindowImpl::hideEvent(QHideEvent *event)
{	
	saveUiSettings();
}

void MainWindowImpl::showEvent(QShowEvent *event)
{	
	loadUiSettings();
};

void MainWindowImpl::close()
{	
	m_bExit = true;
	QMainWindow::close();
}

void MainWindowImpl::configureDlg()
{
	ConfigDlgImpl* dialog = new ConfigDlgImpl(this);
	dialog->setData(m_ftpHandler->host(),
					m_ftpHandler->username(), 
					m_ftpHandler->password(),
					m_ftpHandler->usePassiveMode(),
					m_savePassword);
	dialog->exec();
	if( dialog->result() == QDialog::Accepted )
	{
		m_ftpHandler->setHost( dialog->host() );
		m_ftpHandler->setUsername( dialog->username());
		m_ftpHandler->setPassword( dialog->password());
		m_ftpHandler->setUsePassiveMode( dialog->usePassiveFtp());
		saveConfigSettings();

	}
}

void MainWindowImpl::ftpDownload()
{
	if( m_ftpHandler )
	{
		m_ftpHandler->ftpDownload();
		statusBar()->showMessage(tr("Dowloading tasks config file from ftp"), 2000);
	}
}
	
void MainWindowImpl::ftpUpload()
{
	if( m_ftpHandler )
	{
		m_container->saveData();
		m_ftpHandler->ftpUpload();
		statusBar()->showMessage(tr("Uploading tasks config file to ftp"), 2000);
	}
}

void MainWindowImpl::saveUiSettings()
{	
	m_appSettings->setValue(UI_WINDOW_POS, pos());
	m_appSettings->setValue(UI_WINDOW_SIZE, size());
}

void MainWindowImpl::loadUiSettings()
{
	QPoint pos = m_appSettings->value(UI_WINDOW_POS).toPoint();
	move(pos);
	QSize size =  m_appSettings->value(UI_WINDOW_SIZE).toSize();
	qDebug() << size.width();
	qDebug() << size.height();
	resize(size);
};

void MainWindowImpl::addTaskToList(Task& task, int itemInd )
{
	QTreeWidgetItem* item = new QTreeWidgetItem();
	int ind = 0;
	int priority = task.priority();
	item->setText(0, PriorityList[priority]);
	item->setText(1, task.taskTxt());
	QDate date = task.date();
	QString tmp = date.toString(DateFormat);
	item->setText(2, tmp);
	QString percentDone = QString::number( task.percent() ) + "\%";
	item->setText(3, percentDone );
	
	QTreeWidget* tree;
	//set item
	if( task.type() == eWork )
	{
		item->setIcon(0,QIcon(":/itemw.png"));
		tree = m_officeTasksTree;		
	}
	else
	{
		item->setIcon(0,QIcon(":/itemp.png"));
		tree = m_privateTasksTree;
	}
	if( itemInd == -1)
		ind = sortedIndToInsert(*item, *tree);
	else
		ind = itemInd;

	tree->insertTopLevelItem(ind, item);
	tree->setCurrentItem( item );		
}


void MainWindowImpl::quit()
{	
	m_container->saveData();
	saveConfigSettings();
	saveTreeConfigSettings();
}

int MainWindowImpl::compareItems(const QTreeWidgetItem& item1, const QTreeWidgetItem& item2)
{
	int res = 0;
	int dateRes = 0, dateRes2 = 0;
	int pr1 = PriorityList.key(item1.text(0));
	int pr2 = PriorityList.key(item2.text(0));
	
	QDate currentDate = QDate::currentDate();

	if( pr1 < pr2 )
		return -1;//we've got higher priority here so get it on the top of the list
	else if( pr1 > pr2 )
		return 1;//continue to with next item
	else
	{
		dateRes = QDate::fromString(item1.text(2),DateFormat).daysTo(currentDate);
		dateRes2 = QDate::fromString(item2.text(2),DateFormat).daysTo(currentDate);

		res = dateRes -= dateRes2;
		if( res == 0) 
			return -1;//the same as next one, so should be on the top
		else return res; // continue with the next item
	}
}

int MainWindowImpl::sortedIndToInsert(const QTreeWidgetItem& item, QTreeWidget& tree)
{
	QTreeWidgetItem* treeItem;
	int i = 0;
	for(i = 0; i < tree.topLevelItemCount(); i++)
	{
		treeItem = tree.topLevelItem(i);
		if( compareItems(item, *treeItem) < 0 )
			return i;
	}
	return i;

}

void MainWindowImpl::printPersonal()
{
	if( m_privateTasksTree->topLevelItemCount() > 0)
		print(m_privateTasksTree, tr("Personal TODO"));
	else
		displayMsg( tr("Private task list is empty"));
		
}

void MainWindowImpl::printWork()
{
	if( m_officeTasksTree->topLevelItemCount() > 0 )
		print(m_officeTasksTree, tr("Work TODO"));
	else
		displayMsg( tr("Office task list is empty"));

}

void MainWindowImpl::printBoth()
{
	if( m_officeTasksTree->topLevelItemCount() > 0 )
		print(m_officeTasksTree, tr("Work TODO"), true);
	else if( m_privateTasksTree->topLevelItemCount() > 0 )
		print(m_privateTasksTree, tr("Personal TODO"));
	else
		displayMsg(tr("Lists are empty"));
}

void MainWindowImpl::print(QTreeWidget* tree, QString title, bool both)
{

	if( !tree )
		return;

	QTextEdit* text = new QTextEdit(this);
	QTextCursor cursor(text->textCursor());
	cursor.movePosition(QTextCursor::Start);

	QTextCharFormat textFormat;
	QTextCharFormat boldFormat;
	boldFormat.setFontWeight(QFont::Bold);

	QTextFrame *topFrame = cursor.currentFrame();

	QTextTableFormat tableFormat;
	tableFormat.setBorder(1);
	tableFormat.setCellPadding(2);
	tableFormat.setCellSpacing(2);
	tableFormat.setAlignment(Qt::AlignLeft);
	QTextTable* table;
	
	
	int k = 1;
	if( both )
		k++;

	while( k > 0 )
	{
		if( both && k == 1 )
		{
			if( m_privateTasksTree->topLevelItemCount() > 0 )
			{
				title = tr("personall TODO");
				tree = m_privateTasksTree;
			}
			else
			{				
				printDocument(*text->document());
				delete text;
				return;
			}
		}
		//specify is office or personal
		cursor.insertBlock();
		cursor.insertText(title, boldFormat);	
		cursor.insertBlock();
		
		//draw table
		table = cursor.insertTable(tree->topLevelItemCount()+1, tree->columnCount(), tableFormat);
		
		cursor.setPosition( table->cellAt(0,0).firstCursorPosition().position());
		cursor.insertText(tr("Priority"), boldFormat);

		cursor.setPosition( table->cellAt(0,1).firstCursorPosition().position());
		cursor.insertText(tr("Task"), boldFormat);

		cursor.setPosition( table->cellAt(0,2).firstCursorPosition().position());
		cursor.insertText(tr("Date"), boldFormat);
		
		cursor.setPosition( table->cellAt(0,3).firstCursorPosition().position());
		cursor.insertText(tr("Percent"), boldFormat);

		QTreeWidgetItem* item;
		for( int i=1; i <= tree->topLevelItemCount(); i++)
		{
			item = tree->topLevelItem(i-1);
			for(int j = 0; j < tree->columnCount(); j++)
			{
				cursor.setPosition( table->cellAt(i,j).firstCursorPosition().position());
				cursor.insertText(item->text(j));
			}
		}
		cursor.setPosition(topFrame->lastPosition());
		cursor.insertBlock();
		k--;
	}

	QTextDocument *document = text->document();
	printDocument(*document);
	
	delete text;
}

void MainWindowImpl::printDocument(QTextDocument& document)
{
	QPrinter printer;

	QPrintDialog *dlg = new QPrintDialog(&printer, this);
	if (dlg->exec() != QDialog::Accepted)
	{		
        return;
	}

	document.print(&printer);
}

void MainWindowImpl::keyPressEvent(QKeyEvent *keyPressed)
{
	switch( keyPressed->key() )
	{
	case Qt::Key_Delete:
	case Qt::Key_Backspace:
		{
			deleteTask();
		}
		break;
	}
}

void MainWindowImpl::officeItemClicked(QTreeWidgetItem* item ,int column)
{
	qDebug() << "officeItemClicked";
	m_currentList = m_officeTasksTree;
}

void MainWindowImpl::privateItemClicked(QTreeWidgetItem* item ,int column)
{
	qDebug() << "privateItemClicked";
	m_currentList = m_privateTasksTree;
}

void MainWindowImpl::editItem(QTreeWidgetItem* item,int col)
{
	if( m_currentList && m_currentList->topLevelItemCount() != 0)
	{		
		Task* task = prepareTask( *item );		
		int taskInd = m_container->findTask( *task );

        if( !m_pNewItemDialog )
            m_pNewItemDialog = new NewItemDialogImpl(this);
            
		m_pNewItemDialog->setTask( task );
		m_pNewItemDialog->exec();		
		if( m_pNewItemDialog->result() == QDialog::Accepted)
		{
			//we are editing item, update data in container, then update list view
			int ind = m_currentList->indexOfTopLevelItem( item );
			m_container->editTask( taskInd, *task );			
			item = m_currentList->takeTopLevelItem(ind);
			addTaskToList( *task );
			delete item;			
		}
		delete task;
	}
	else
		displayMsg(tr("Task should be selected"));
}

void MainWindowImpl::addTask()
{
    if(!m_pNewItemDialog)
        m_pNewItemDialog = new NewItemDialogImpl(this);
    
    Task* task = new Task();
    task->init();
    
    m_pNewItemDialog->setTask(task);
	m_pNewItemDialog->exec();
	if( m_pNewItemDialog->result() == QDialog::Accepted )
	{
		addTaskToList(*task);
		//list take ownerships
		m_container->addTask(task);
	}
    delete task;
}

void MainWindowImpl::editTask()
{
	if( m_currentList && m_currentList->topLevelItemCount() != 0)
	{
		QTreeWidgetItem* item = m_currentList->topLevelItem(m_currentList->currentIndex().row());
		editItem(item,0);
	}
	else
		displayMsg(tr("Task should be selected"));
}



void MainWindowImpl::deleteTask()
{
	if(m_currentList && m_currentList->topLevelItemCount() != 0)
	{
		int ind = m_currentList->currentIndex().row();
		QTreeWidgetItem* item = m_currentList->topLevelItem( ind );
		Task* task = prepareTask(*item);
		m_container->deleteTask(*task);
		delete task;
		item = m_currentList->takeTopLevelItem( ind );
		delete item;
	}
	else
		displayMsg(tr("Task should be selected"));
}

Task* MainWindowImpl::prepareTask(QTreeWidgetItem& item)
{	
	TaskType type = itemType(item);	
	QString tmp = item.text(2);
	QDate date = QDate::fromString(tmp,DateFormat);
	bool ok = true;
	tmp = item.text(3);
	tmp = tmp.left(tmp.indexOf("\%"));
	int percent = tmp.toInt(&ok);
	if( !ok )
		qDebug() << "percent not cast to int";
	//caller deletes it
	Task* task = new Task(item.text(1),date, type,(TaskPriority)PriorityList.key(item.text(0)), percent );
	return task;
}

void MainWindowImpl::displayMsg(const QString& string)
{
	QMessageBox::warning(this, tr("QWhatToDo"), string, QMessageBox::Ok);
}

TaskType MainWindowImpl::itemType(QTreeWidgetItem& item)
{
	if( m_officeTasksTree->indexOfTopLevelItem(&item) != -1 )
		return eWork;
	else
		return ePersonal;
}

void MainWindowImpl::aboutQt()
{
	QMessageBox::aboutQt(this);
}

void MainWindowImpl::aboutQWhatToDo()
{
	QMessageBox::about(this, tr("About QWhatToDo"), tr("QWhatToDo is a simple application which allow... "));
}

void MainWindowImpl::ftpDone()
{
	QString info;
	if( m_ftpHandler->isDownloading())
	{
		info = tr("Downloading ");
		//as we done here, container should parse file and add to the list task which are not already on the list
		m_container->loadData( DATAFILEFTP );
	}
	else
	{
		info = tr("Uploading ");
	}
	info += tr("todo config file finished successful");

	statusBar()->showMessage(info,5000);
}

void MainWindowImpl::ftpError(const QString& msg)
{
	QString info;
	if( m_ftpHandler->isDownloading())
		info = tr("Downloading ");
	else
		info = tr("Uploading ");

	info += tr("todo config file failed");
	info += "( " + msg + " )";

	statusBar()->showMessage(info,5000);
}

void MainWindowImpl::ftpProgress(qint64 done, qint64 total)
{
	QString info;
	if( m_ftpHandler->isDownloading())
		info = tr("Downloading... ");
	else
		info = tr("Uploading... ");

	int pr = (done * 100) / total;
	info += QString::number(pr);
	info +=" \%";

	statusBar()->showMessage(info,2000);
}

//EOF
